package com.mydemo.springlearning.functions.memoryshare.service;

import com.mydemo.springlearning.functions.CRUDdemo.entity.User;
import com.mydemo.springlearning.functions.memoryshare.mapper.BigUserMapper;
import com.mydemo.springlearning.functions.memoryshare.entity.BigUser;
import com.mydemo.springlearning.functions.memoryshare.entity.UserShare;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.cursor.Cursor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.StopWatch;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

@Service
@Slf4j
public class BigUserServiceImpl implements BigUserService {
    @Autowired
    PlatformTransactionManager transactionManager;
    @Autowired
    BigUserMapper bigUserMapper;

    /**
     * 得到所有用户的数量
     *
     * @return 用户数量
     */
    @Override
    public String getTotalUserAmount() {
        StopWatch userWatch = new StopWatch();
        userWatch.start();
        List<BigUser> allBigUser = this.getAllBigUser();
        userWatch.stop();
        int size = allBigUser.size();
        double totalTimeSeconds = userWatch.getTotalTimeSeconds();
        return "用户数量：" + size + "，查询耗时: " + totalTimeSeconds;
    }

    /**
     * 流式查询
     *
     * @return
     */
    @Override
    public String getTotalUserAmountByStream() {
        StopWatch userWatch = new StopWatch();
        userWatch.start();
        List<BigUser> allBigUser = this.getAllBigUserByStream();
        userWatch.stop();
        int size = allBigUser.size();
        double totalTimeSeconds = userWatch.getTotalTimeSeconds();
        return "流式查询 用户数量：" + size + "，查询耗时: " + totalTimeSeconds;
    }

    /**
     * 流式查询+多线程加结果到list
     *
     * @return
     */
    @Override
    public String getTotalUserAmountByStreamThread() {
        StopWatch userWatch = new StopWatch();
        userWatch.start();
        List<BigUser> allBigUser = this.getAllBigUserByStreamThread();
        userWatch.stop();
        int size = allBigUser.size();
        double totalTimeSeconds = userWatch.getTotalTimeSeconds();
        return "流式(多线程)查询 用户数量：" + size + "，查询耗时: " + totalTimeSeconds;
    }

    private List<BigUser> getAllBigUserByStreamThread() {
        StopWatch queryWatch = new StopWatch();
        StopWatch totalWatch = new StopWatch();
        StopWatch addWatch = new StopWatch();
        totalWatch.start();
        List<BigUser> allBigUser = new ArrayList<>();
        queryWatch.start();
        Cursor<BigUser> cursor = bigUserMapper.getBigUserByStream();
        queryWatch.stop();
        log.warn("流式查询 查询BigUser耗时：" + queryWatch.getTotalTimeSeconds());
        addWatch.start();
        try {
            cursor.forEach(allBigUser::add);
            // 也可以使用迭代器：Iterator<Object> iterator = cursor.iterator();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != cursor) {
                try {
                    cursor.close();
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }
            }
        }

        addWatch.stop();
        log.warn("流式查询 装填BigUser耗时：" + addWatch.getTotalTimeSeconds());
        totalWatch.stop();
        log.warn("流式查询 总共BigUser耗时：" + totalWatch.getTotalTimeSeconds());
        return allBigUser;
    }

    @Override
    public void add(User user) throws InterruptedException {
        Thread.sleep(15000);
        UserShare.userList.add(user);

    }

    @Override
    public List<User> get() {
        return UserShare.userList;
    }

    @Override
    public String delete(String name) {
        if (UserShare.userList.size() < 1) {
            return "没有user";
        }
        boolean flag = false;
        for (int i = UserShare.userList.size() - 1; i >= 0; i--) {
            if (UserShare.userList.get(i).getUserName().equals(name)) {
                UserShare.userList.remove(i);
                flag = true;
            }
        }

        return flag ? "删除成功" : "没有找到user";
    }

    /**
     * 查询得到所有未删除的BigUser
     *
     * @return ds_deleted=0
     */
    @Override
    public List<BigUser> getAllBigUser() {
        StopWatch watch = new StopWatch();
        watch.start();
        List<BigUser> allBigUser = bigUserMapper.getAllBigUser();
        watch.stop();
        log.warn("查询BigUser耗时：" + watch.getTotalTimeSeconds());
        return allBigUser;
    }

    /**
     * <流式查询>查询得到所有未删除的BigUser
     *
     * @return ds_deleted=0
     */
    @Override
//    @Transactional 必须controller层加
    public List<BigUser> getAllBigUserByStream() {
        StopWatch queryWatch = new StopWatch();
        StopWatch totalWatch = new StopWatch();
        StopWatch addWatch = new StopWatch();
        totalWatch.start();
        List<BigUser> allBigUser = new ArrayList<>();
        queryWatch.start();
        Cursor<BigUser> bigUserByStream = bigUserMapper.getBigUserByStream();
        queryWatch.stop();
        log.warn("流式查询 查询BigUser耗时：" + queryWatch.getTotalTimeSeconds());
        addWatch.start();
        bigUserByStream.forEach(bigUser -> {
            allBigUser.add(bigUser);
        });
        addWatch.stop();
        log.warn("流式查询 装填BigUser耗时：" + addWatch.getTotalTimeSeconds());
        totalWatch.stop();
        log.warn("流式查询 总共BigUser耗时：" + totalWatch.getTotalTimeSeconds());
        return allBigUser;
    }



    /**
     * 查询得到所有未删除的BigUser
     *
     * @return ds_deleted=0
     */
    @Override
    public List<BigUser> getAllBigUserLimit(int limit) {
        TransactionTemplate transactionTemplate =
                new TransactionTemplate(transactionManager); // 1
        StopWatch watch = new StopWatch();
        watch.start();
        List<BigUser> allBigUser = new ArrayList<>();
        transactionTemplate.execute(status -> {
            try (
                    Cursor<BigUser> bigUserLimit = bigUserMapper.getBigUserLimit(limit);
            ) {
                bigUserLimit.forEach(allBigUser::add);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        });

        watch.stop();
        log.warn("查询装配BigUser耗时：" + watch.getTotalTimeSeconds());
        return allBigUser;
    }

    /**
     * 流式查询+多线程加结果到list
     *
     * @return
     */
    @Override
    public List<BigUser> getAllBigUserByMultiThread(int limit) {
        TransactionTemplate transactionTemplate =
                new TransactionTemplate(transactionManager); // 1
        StopWatch watch = new StopWatch();
        List<BigUser> allBigUser = new ArrayList<>();
        watch.start();
        transactionTemplate.execute(status -> {
            Cursor<BigUser> bigUserLimit = bigUserMapper.getBigUserLimit(limit);
            addUser2List(allBigUser, bigUserLimit);
            return null;
        });
        watch.stop();
        log.warn("查询装配BigUser耗时：" + watch.getTotalTimeSeconds());
        return allBigUser;
    }

    private void addUser2List(List<BigUser> allBigUser, Cursor<BigUser> bigUserLimit) {
        ExecutorService exs = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors() / 2 + 1,
                Runtime.getRuntime().availableProcessors(),
                600,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>());
        List<CompletableFuture> cfs = new ArrayList<>();
        bigUserLimit.forEach(bigUser -> {
            CompletableFuture.supplyAsync(() -> calc(allBigUser, bigUser), exs).whenComplete((obj, e) -> {
            });
     /*   CompletableFuture[] cfs = userDeptRelationList
                .stream()
                .map(userDeptRelationDTO -> CompletableFuture.supplyAsync(() -> calc(userDeptRelationDTO, oua), exs)
                        .whenComplete((obj, e) -> {
                        }))
                .toArray(CompletableFuture[]::new);
        CompletableFuture.allOf(cfs).join();*/
        });
        CompletableFuture.allOf(cfs.toArray(new CompletableFuture[0])).join();
        exs.shutdown();
    }

    public boolean calc(List<BigUser> allBigUser, BigUser b) {
        allBigUser.add(b);
        return true;
    }
}
